package com.mashibing.api.controller;

/**
 * @ClassName:SmsController
 * @author:[开发者名称]
 * @Description:[类的功能描述]
 * @Date:2025/9/13/20:41
 * @Version:1.0
 */

import com.alibaba.cloud.commons.lang.StringUtils;
import com.mashibing.api.dto.SingleSendDTO;

import com.mashibing.api.filter.CheckFilterContext;
import com.mashibing.api.util.ResultVOUtil;
import com.mashibing.api.vo.ResultVO;
import com.mashibing.common.constant.RabbitMQConstants;
import com.mashibing.common.enums.ExceptionEnums;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.common.util.SnowFlakeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * **请求路径&方式**
 *
 * **请求路径：** https://sms.beaconcloud.com/v1/sms/single_send
 *
 * **请求方式：** POST
 *
 * **请求头信息**
 *
 * | 请求头      | 请求信息                       |
 * | ----------- | ------------------------------ |
 * | Accept      | application/json;charset=utf-8 |
 * | ContentType | application/json;charset=utf-8 |
 *
 * **请求参数：**
 *
 * | 参数名 | 类型    | 是否必传 | 说明                                     | 示例                             |
 * | ------ | ------- | -------- | ---------------------------------------- | -------------------------------- |
 * | apikey | string  | 是       | 由服务方提供，可以在后台首页中查看       | 887559db54d911edba520242ac120002 |
 * | mobile | string  | 是       | 接收的手机号，仅支持单号码发送           | 18888888888                      |
 * | text   | string  | 是       | 需要发送的短信内容，需要与签名和模板匹配 | 【烽火云】 您的验证码是 1234     |
 * | uid    | string  | 否       | 您业务系统内的ID，回调时会携带此参数     | 10086                            |
 * | state  | integer | 是       | 0-验证码短信 1-通知类短信 2-营销类短信   | 0                                |
 *
 * **响应数据：**
 *
 * | 名称  | 类型    | 说明                                                         |
 * | ----- | ------- | ------------------------------------------------------------ |
 * | code  | integer | 0代表接收成功，其他code代表出错                              |
 * | msg   | string  | 例如“接收成功”，代表短信正在发送，或者是响应具体的错误信息   |
 * | count | integer | 短信的计费条数（70个字一条，超出70个字，按照67个字一条发送） |
 * | fee   | long    | 扣费的金额，单位：厘 ，RMB                                   |
 * | uid   | string  | 客户请求携带的uid信息                                        |
 * | sid   | long    | 平台内的短信id，64位整型                                     |
 *
 * **常见的状态码：**
 *
 * | 状态码 | 说明                        |
 * | ------ | --------------------------- |
 * | 0      | 代表接收成功，短信发送ing…… |
 * | -1     | 非法的apikey                |
 * | -2     | 请求的ip不在白名单内        |
 * | -3     | 无可用签名                  |
 * | -4     | 无可用模板                  |
 * | -5     | 手机号格式不正确            |
 * | -6     | 客户余额不足                |
 *
 * **单条短信接口模块的校验项：**
 *
 * * 校验apikey
 * * 校验请求的ip地址是否是白名单
 * * 校验短信的签名
 * * 校验短信的模板
 * * 校验手机号的格式合法性
 * * 校验客户剩余的金额是否充足
 */
@RestController
@RequestMapping("/sms")
@Slf4j
@RefreshScope//动态获取配置文件信息
public class SmsController {
    @Autowired
    CheckFilterContext checkFilterContext;
    @Autowired
    SnowFlakeUtil snowFlakeUtil;
    @Autowired
    RabbitTemplate rabbitTemplate;


    @PostMapping(value = "/single_send",produces = "application/json;charset=utf-8")
    public ResultVO sinleSend(@RequestBody @Validated SingleSendDTO singleSendDTO, BindingResult bindingResult ,HttpServletRequest req){
        //1.校验参数
        if (bindingResult.hasErrors()){
           String msg = bindingResult.getFieldError().getDefaultMessage();
           log.info("接口模块---单条短信Controller 参数不合法：msg = {}",msg);
           ResultVO resultVO = ResultVOUtil.error(ExceptionEnums.PARAMETER_ERROR.getCode(),msg);
           return resultVO;

        }
        //=========================获取用户的ip地址==============================

        String ip = this.getRealIP(req);
        System.out.println(req.getRemoteAddr()+"----------------------"+ip);


        //=========================构建StandardSubmit，各种封装校验==============================
        StandardSubmit standardSubmit = StandardSubmit.builder()
                .realIP(ip)  //请求地址
                .apikey(singleSendDTO.getApikey())   //客户的apikey  客户唯一标识id
                .mobile(singleSendDTO.getMobile())   //手机号
                .text(singleSendDTO.getText())       //短信内容 包含短信签名
                .state(singleSendDTO.getState())     //短信类型  0-验证码短信 1-通知类短信 2-营销类短信
                .uid(singleSendDTO.getUid()).build();//客户业务系统内的ID  uuid

        checkFilterContext.check(standardSubmit);

//========================基于雪花算法生成唯一id，并添加到StandardSubmit对象中=========================================
        standardSubmit.setSequenceId(snowFlakeUtil.nextId());


        //=========================发送到MQ，交给策略模块处理=========================================
        rabbitTemplate.convertAndSend(RabbitMQConstants.SMS_PRE_SEND,standardSubmit,new CorrelationData(standardSubmit.getSequenceId().toString()));
        return  ResultVOUtil.ok();
    }

    /**
     * 客户端IP地址的请求头信息，多个用','隔开。
     */
    @Value("${headers}")
    private String headers;

    /**
     * 基于请求头获取信息时，可能获取到的未知信息
     */
    private final String UNKNOW = "unknow";

    /**
     * 如果是当前请求头获取IP地址，需要截取到第一个','未知
     */
    private final String X_FORWARDED_FOR = "x-forwarded-for";

    /**
     * 获取客户端真实的IP地址
     * @param req
     * @return
     */
    private String getRealIP(HttpServletRequest req) {
        //1. 声明返回的ip地址
        String ip;

        //2. 遍历请求头，并且通过req获取ip地址
        for (String header : headers.split(",")) {
            // 健壮性校验
            if (!StringUtils.isEmpty(header)) {
                // 基于req获取ip地址
                ip = req.getHeader(header);
                // 如果获取到的ip不为null，不为空串，并且不为unknow，就可以返回
                if (!StringUtils.isEmpty(ip) && !UNKNOW.equalsIgnoreCase(ip)) {
                    // 判断请求头是否是x-forwarded-for
                    if (X_FORWARDED_FOR.equalsIgnoreCase(header) && ip.indexOf(",") > 0) {
                        ip = ip.substring(0,ip.indexOf(","));
                    }
                    // 返回IP地址
                    return ip;
                }
            }
        }

        //3. 如果请求头都没有获取到IP地址，直接基于传统的方式获取一个IP
        return req.getRemoteAddr();
    }

    /*
    private String getRealIP(HttpServletRequest req) {

        //0. 声明真实IP地址
        String  ip;

        //1. 基于x-forwarded-for请求头获取IP地址
        String ips = req.getHeader("x-forwarded-for");
        //  直接基于第一个,的位置，截取需要的IP地址
        if (StringUtils.isEmpty(ips) || "unknow".equalsIgnoreCase(ips)) {
            if(ips.contains(",")){
                return ips.substring(0, ips.indexOf(","));
            }else{
                return ips;
            }
        }

        // 2. 基于请求头获取IP地址，基于request请求头获取信息时，除了null和空串外，还有可能拿到unknow，
        ip = req.getHeader("x-real-ip");
        if (StringUtils.isEmpty(ip) || "unknow".equalsIgnoreCase(ip)){
            // x-real-ip没拿到，考虑一下其他的代理服务器
            //3.  Apache的服务器，请求头中携带真实IP的名称是 proxy-client-ip
            ip = req.getHeader("proxy-client-ip");
        }

        //4. 如果real没有拿到，判断apache是否拿到了。
        if (StringUtils.isEmpty(ip) || "unknow".equalsIgnoreCase(ip)){
            // 5. 如果Apache服务器没拿到，考虑一手WebLogic, wl-proxy-client-ip
            ip = req.getHeader("wl-proxy-client-ip");
        }

        //6. 判断WebLogic有木有拿到IP
        if (StringUtils.isEmpty(ip) || "unknow".equalsIgnoreCase(ip)){
            //7. 基于其他的代理服务器的方式获取请求头的IP地址
            ip = req.getHeader("http_client_ip");
        }
        //8. 如果上诉方式都获取不到，
        if (StringUtils.isEmpty(ip) || "unknow".equalsIgnoreCase(ip)){
            // 9. 基于传统方式获取IP
            ip = req.getRemoteAddr();
        }
        //10. 返回
        return ip;
    }*/

}
